package com.apobates.jforum.grief.schema2doc.reactive.dialect;

import com.apobates.jforum.grief.schema2doc.core.SchemaTableStrategy;
import com.apobates.jforum.grief.schema2doc.core.entity.Column;
import com.apobates.jforum.grief.schema2doc.core.entity.Nullable;
import com.apobates.jforum.grief.schema2doc.core.entity.PrimayKey;
import com.apobates.jforum.grief.schema2doc.core.entity.Table;
import com.apobates.jforum.grief.schema2doc.core.schema.SchemaDialect;
import com.apobates.jforum.grief.schema2doc.reactive.schema.AbstractRxJavaQueryExecutor;
import io.reactivex.Flowable;
import io.reactivex.Single;
import org.davidmoten.rx.jdbc.Database;
import org.jooq.DSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * RxJava2的MariaDB的结果集供应商
 * https://github.com/davidmoten/rxjava-jdbc
 */
public class RxJavaMariaDBExecutor extends AbstractRxJavaQueryExecutor {
    private final static Logger logger = LoggerFactory.getLogger(RxJavaMariaDBExecutor.class);

    protected RxJavaMariaDBExecutor(Database db, SchemaDialect dialect) {
        super(db, dialect);
    }

    @Override
    protected Flowable<Table> getTables(Database db, Optional<String> dbName, Optional<String> schema, SchemaTableStrategy tableStrategy) throws IllegalArgumentException {
        // https://mariadb.com/kb/en/information-schema-tables-table/
        String sql = "SELECT TABLE_NAME AS tableName, TABLE_COMMENT AS remarks FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = :dbname";
        if(tableStrategy.sql(SchemaDialect.MariaDB).isPresent()){
            sql+= " AND " + tableStrategy.sql(SchemaDialect.MariaDB).get().replaceAll(SchemaTableStrategy.placeholder, "TABLE_NAME");
        }
        logger.debug("[RxJava-MariaDB-Table]execute sql statement::"+sql);
        return db.select(sql).parameter("dbname", dbName.get()).get(record -> {
            // String dbName, String tableName, String remarks
            return Table.noSchema(
                    0,
                    dbName.get(),
                    record.getString("tableName"),
                    record.getString("remarks"));
        }).filter(table->tableStrategy.filter().test(table.getTableName()));
    }

    @Override
    protected Single<List<Column>> getColumns(Database db, Table table) {
        // https://mariadb.com/kb/en/information-schema-columns-table/
        String sql = "SELECT " +
                "COLUMN_NAME AS columnName, " +
                "DATA_TYPE AS typeName, " +
                "REPLACE(REPLACE(REPLACE(COLUMN_TYPE, DATA_TYPE, ''), '(', ''), ')', '') AS columnSize, " +
                "IF(IS_NULLABLE='NO','2','1') AS nullable, " +
                "COLUMN_COMMENT AS remarks, " +
                "COLUMN_DEFAULT AS columnDef, " +
                "IF(COLUMN_KEY='PRI','1','2') AS pk, " +
                "NUMERIC_SCALE AS decimalDigits " +
                "FROM INFORMATION_SCHEMA.COLUMNS " +
                "WHERE TABLE_SCHEMA = :dbname AND TABLE_NAME = :tablename";
        logger.debug("[RxJava-MariaDB-COLUMN]execute sql statement::"+sql);
        // Fetch results using jOOQ
        return db.select(sql).parameter("dbname", table.getDbName()).parameter("tablename", table.getTableName()).get(record -> {
            // Basic:: String columnName, String typeName, String columnSize, Nullable nullable, String remarks
            return Column.basic(
                            record.getString("columnName"),
                            record.getString("typeName"),
                            record.getString("columnSize"),
                            Nullable.of(record.getInt("nullable")),
                            record.getString("remarks"))
                    .toFull(
                            record.getString("decimalDigits"),
                            PrimayKey.of(record.getInt("pk")),
                            record.getString("columnDef")); // String decimalDigits, PrimayKey pk, String columnDef
        }).toList();
    }
}
